package com.google.code.p.restrpc.client.proxy;

import java.lang.reflect.Method;
import java.util.List;

import com.google.code.p.restrpc.RestInvoker;
import com.google.code.p.restrpc.RpcContext;
import com.google.code.p.restrpc.RpcRequest;
import com.google.code.p.restrpc.RpcResponse;
import com.google.code.p.restrpc.annotation.Implementor;
import com.google.code.p.restrpc.client.cluster.DefaultClusteredRpcContext;
import com.google.code.p.restrpc.client.cluster.FailureRecoveryStrategy;
import com.google.code.p.restrpc.client.cluster.FailureRecoveryStrategyManager;
import com.google.code.p.restrpc.client.loadbalance.LoadBalanceStrategy;
import com.google.code.p.restrpc.client.loadbalance.LoadBalanceStrategyManager;

/**
 * @author dz
 */
public class CachedClusteredRpcInvoker extends AbstractRpcInvoker {
    
    /**
     * @param restInvoker
     * @param repository
     */
    public CachedClusteredRpcInvoker(RestInvoker restInvoker) {
        super(restInvoker);
    }
    
    /**
     * 
     */
    public Object invoke(RpcContext rpcContext, List<RpcRequest> requests) {
        FailureRecoveryStrategy failureRecoveryStrategy = FailureRecoveryStrategyManager.getInstance()
                                                                                        .getStrategy(rpcContext.getFailureRecovery());
        if (failureRecoveryStrategy == null) {
            throw new IllegalArgumentException("Unsupported FailureRecovery " + rpcContext.getFailureRecovery());
        }
        
        LoadBalanceStrategy loadBalanceStrategy = LoadBalanceStrategyManager.getInstance()
                                                                            .getStrategy(rpcContext.getLoadBalance());
        if (loadBalanceStrategy == null) {
            throw new IllegalArgumentException("Unsupported LoadBalance " + rpcContext.getLoadBalance());
        }
        
        RpcResponse response = failureRecoveryStrategy.invoke(new DefaultClusteredRpcContext(getRestInvoker(),
                                                                                             rpcContext,
                                                                                             loadBalanceStrategy),
                                                              requests);
        Method method = rpcContext.getTargetMethod();
        Implementor implementor = method.getAnnotation(Implementor.class);
        return getRpcResponseHandler().handle(response,
                                              (implementor != null) ? implementor.value()
                                                                   : method.getReturnType());
    }
    
}
